package saxion.speelveld.spaceengineer.database;

import java.util.ArrayList;

import saxion.speelveld.spaceengineer.model.Building;
import saxion.speelveld.spaceengineer.model.Difficulties;
import saxion.speelveld.spaceengineer.model.Game;
import saxion.speelveld.spaceengineer.model.RemovedBuilding;
import saxion.speelveld.spaceengineer.model.Resource;
import saxion.speelveld.spaceengineer.model.Tile;
import saxion.speelveld.spaceengineer.model.TradePlanet;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class GameDAO
{
	private SQLiteDatabase database;

	private GameDB dbHelper;

	private ResourceDAO resourceDatasource;

	private BuildingDAO buildingDatasource;

	private BuildingTypeDAO buildingTypeDatasource;

	private TileDAO tileDatasource;

	private TradePlanetsDAO tradePlanetsDatasource;

	public GameDAO(Context context)
	{
		dbHelper = new GameDB(context);
		resourceDatasource = new ResourceDAO(context);
		buildingDatasource = new BuildingDAO(context);
		tileDatasource = new TileDAO(context);
		tradePlanetsDatasource = new TradePlanetsDAO(context);
		buildingTypeDatasource = new BuildingTypeDAO(context);
	}

	public GameDAO(Context context, boolean initOtherConnections)
	{
		dbHelper = new GameDB(context);
		if (initOtherConnections == true)
		{
			resourceDatasource = new ResourceDAO(context);
			buildingDatasource = new BuildingDAO(context);
			tileDatasource = new TileDAO(context);
		}
	}

	/**
	 * Open the database connection.
	 * 
	 * @throws SQLException
	 */
	public void open() throws SQLException
	{
		database = dbHelper.getWritableDatabase();
	}

	/**
	 * Close the database connection.
	 */
	public void close()
	{
		dbHelper.close();
	}

	public int createNewSaveGame(Game game)
	{
		int gameId = 0;

		// save game data ---------------- POSSIBLE!
		ContentValues values = new ContentValues();
		values.put(GameDB.COLUMN_GAMEDIFFICULTY, game.getDifficulty().ordinal());
		values.put(GameDB.COLUMN_GAMETILESINHEIGHT, game.getField()[0].length);
		values.put(GameDB.COLUMN_GAMETILESINWIDTH, game.getField().length);
		values.put(GameDB.COLUMN_GAMEVIEWCURSORX, game.getViewCursorX());
		values.put(GameDB.COLUMN_GAMEVIEWCURSORY, game.getViewCursorY());
		values.put(GameDB.COLUMN_GAMETIMETICKS, game.getGameTime());
		gameId = (int) database.insert(GameDB.TABLE_NAME, null, values);

		return gameId;
	}

	/**
	 * Alleen game data updaten, dus niet alle arrays, arraylists etc.
	 * 
	 * @param game
	 * @param gameId
	 */
	public void saveExistingGameData(Game game, int gameId)
	{
		// Log.w("saveExistingGameData", "gameTime: " + game.getGameTime() + ", x:" + game.getViewCursorX() + ", y:"
		// + game.getViewCursorY());
		if (checkIfGameExists(gameId) == true)
		{
			ContentValues values = new ContentValues();
			values.put(GameDB.COLUMN_GAMETIMETICKS, game.getGameTime());
			values.put(GameDB.COLUMN_GAMEVIEWCURSORX, game.getViewCursorX());
			values.put(GameDB.COLUMN_GAMEVIEWCURSORY, game.getViewCursorY());
			database.update(GameDB.TABLE_NAME, values, GameDB.COLUMN_ID + "=?", new String[] { gameId + "" });
		}
	}

	/**
	 * Ook resources, gebouwen, trade deals etc updaten :).
	 * 
	 * @param game
	 * @param gameId
	 */
	public void saveExistingGameDataAndChildren(Game game, int gameId)
	{
		// save game data

		// Log.w("saveExistingGameDataAndChildren", "started with game id " + gameId);
		// Log.e("saveExistingGameDataAndChildren", "Saving Game data.");
		saveExistingGameData(game, gameId);

		// Log.w("saveExistingGameDataAndChildren", "Saving Game data done.");

		// save resources

		// Log.w("saveExistingGameDataAndChildren", "Saving resources");

		if (game.isResourcesUpdated() == true)
		{
			try
			{
				resourceDatasource.open();
				resourceDatasource.beginTransactionMode();
				for (Resource resource : game.getResourceArray())
				{
					resourceDatasource.putResourceForGame(gameId, resource);
				}
				resourceDatasource.setTransactionModeSuccesfull();
			}
			finally
			{
				resourceDatasource.endTransactionMode();
				resourceDatasource.close();
			}
		}

		// Log.w("saveExistingGameDataAndChildren", "Saving resources done.");

		// save buildings

		// Log.w("saveExistingGameDataAndChildren", "Saving buildings");

		if (game.isBuildingsUpdated() == true)
		{
			try
			{
				buildingDatasource.open();
				buildingDatasource.beginTransactionMode();

				int buildingArrayListSize = game.getBuildings().size();
				for (int i = 0; i < buildingArrayListSize; i++)
				{
					buildingDatasource.putBuilding(gameId, game.getBuildings().get(i), i);

				}

				// delete buildings
				if (game.getRemovedBuildings().size() > 0)
				{
					for (RemovedBuilding removedBuilding : game.getRemovedBuildings())
					{

						boolean succeeded = buildingDatasource.removeBuilding(gameId,
							removedBuilding.getRemovedBuildingIndex(), removedBuilding.getRemovedBuilding());
						if (succeeded == true)
						{

						}
					}
				}

				game.setBuildingsUpdated(false);
				buildingDatasource.setTransactionModeSuccesfull();

			}
			finally
			{
				buildingDatasource.endTransactionMode();
				buildingDatasource.close();
			}
		}

		// Log.w("saveExistingGameDataAndChildren", "Saving buildings done.");

		// save tiles

		if (Game.isTilesUpdated() == true)
		{
			int updatedTileCount = 0;
			Log.w("saveExistingGameDataAndChildren", "Saving tiles");
			try
			{
				tileDatasource.open();
				tileDatasource.beginTransactionMode();
				for (int x = 0; x < game.getField().length; x++)
				{
					for (int y = 0; y < game.getField()[0].length; y++)
					{
						Tile tile = game.getField()[x][y];
						if (tile.isDirty() == true)
						{
							tileDatasource.PutTile(gameId, tile, x, y, true);
							game.getField()[x][y].setDirty(false);
							updatedTileCount = updatedTileCount + 1;
						}
					}
				}
				Game.setTilesUpdated(false);
				tileDatasource.setTransactionModeSuccesfull();
			}
			finally
			{
				tileDatasource.endTransactionMode();
				tileDatasource.close();
			}

			// Log.w("saveExistingGameDataAndChildren", "Saving tiles done. (" + updatedTileCount + ")");
		}
		// Log.w("saveExistingGameDataAndChildren", "done with method.");

	}

	public Game loadExistingGame(int gameId)
	{
		Cursor cursor = database.rawQuery("SELECT * FROM " + GameDB.TABLE_NAME + " WHERE " + GameDB.COLUMN_ID + " = "
			+ gameId, null);
		Log.i("loadExistingGame", "loading game id: " + gameId);
		cursor.moveToFirst();
		Game game = CursorToGame(cursor, true, true, true, true);
		game.setNewGame(false);
		cursor.close();
		return game;
	}

	public int getCount()
	{
		Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM " + GameDB.TABLE_NAME, null);
		cursor.moveToFirst();

		return cursor.getInt(0);
	}

	public ArrayList<Game> getAllGames(boolean getResourcesArray, boolean getBuildingArrayList,
		boolean getTradePlantsArray, boolean getTileArray)
	{
		ArrayList<Game> games = new ArrayList<Game>();

		Cursor cursor = database.rawQuery("SELECT * FROM " + GameDB.TABLE_NAME, null);
		cursor.moveToFirst();

		while (cursor.isAfterLast() == false)
		{
			games.add(CursorToGame(cursor, getResourcesArray, getBuildingArrayList, getTradePlantsArray, getTileArray));
			cursor.moveToNext();
		}

		cursor.close();

		return games;
	}

	private Game CursorToGame(Cursor cursor, boolean getResourcesArray, boolean getBuildingArrayList,
		boolean getTradePlanetsArray, boolean getTileArray)
	{
		Game game = null;
		Resource[] resourceArray = null;
		ArrayList<Building> buildingList = null;
		Tile[][] gameField = null;
		TradePlanet[] tradePlanets = null;
		ArrayList<TradePlanet> tradePlantsAL = null;

		Log.i("CursorToGame", "starting with parameters: resources: " + getResourcesArray +
			", buildings: " + getBuildingArrayList + ", tradeplanets: " + getTradePlanetsArray + ", " +
			"tiles: " + getTileArray);

		Difficulties difficultie = Difficulties.values()[cursor.getInt(cursor
			.getColumnIndex(GameDB.COLUMN_GAMEDIFFICULTY))];
		cursor.getInt(cursor.getColumnIndex(GameDB.COLUMN_GAMETILESINHEIGHT));
		cursor.getInt(cursor.getColumnIndex(GameDB.COLUMN_GAMETILESINWIDTH));
		int x = cursor.getInt(cursor.getColumnIndex(GameDB.COLUMN_GAMEVIEWCURSORX));
		int y = cursor.getInt(cursor.getColumnIndex(GameDB.COLUMN_GAMEVIEWCURSORY));
		int gameTime = cursor.getInt(cursor.getColumnIndex(GameDB.COLUMN_GAMETIMETICKS));
		int gameId = cursor.getInt(cursor.getColumnIndex(GameDB.COLUMN_ID));

		if (getResourcesArray == true)
		{
			resourceDatasource.open();
			resourceArray = resourceDatasource.getResourcesForGame(gameId);
			Log.i("CursorToGame", "loaded " + resourceArray.length + " resources from db.");
			resourceDatasource.close();
		}
		if (getBuildingArrayList == true)
		{
			Log.i("CursorToGame", "Loading buildings.");
			buildingTypeDatasource.open();
			buildingDatasource.open();
			buildingList = buildingDatasource.getAllBuildingsForGame(gameId);
			buildingDatasource.close();
			buildingTypeDatasource.close();
		}
		if (getTradePlanetsArray == true)
		{
			tradePlanetsDatasource.open();
			tradePlantsAL = tradePlanetsDatasource.getAllTradePlanetsForGame(gameId);
			tradePlanets = tradePlantsAL.toArray(new TradePlanet[tradePlantsAL.size()]);
			tradePlantsAL = null;
			tradePlanetsDatasource.close();
		}
		if (getTileArray == true)
		{
			tileDatasource.open();
			gameField = tileDatasource.GetTileArrayForGame(gameId, buildingList);
			tileDatasource.close();
		}

		game = new Game(gameField, buildingList, gameTime, difficultie, resourceArray, tradePlanets);
		game.setGameId(gameId);
		game.setViewCursorNoUpdate(x, y);
		if (getBuildingArrayList == true && game.getBuildings().size() > 0)
		{
			game.setInfOrBuildingConnected(game.getBuildings().get(0).getBuildingPointInFieldX(), game.getBuildings()
				.get(0).getBuildingPointInFieldY(), game.getBuildings().get(0));
		}
		return game;
	}

	public boolean checkIfGameExists(int gameId)
	{
		Cursor cursor = database.rawQuery("SELECT * FROM " + GameDB.TABLE_NAME + " WHERE " + GameDB.COLUMN_ID + " = "
			+ gameId, null);
		cursor.moveToFirst();

		if (cursor.getCount() == 1)
		{
			cursor.close();
			return true;
		}
		else
		{
			cursor.close();
			return false;
		}
	}
}
